package org.tri.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.*;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Cascade;

/**
 * La clase {@code Establecimiento} almacena los datos pertinentes de un establecimiento perteneciente a un productor
 * @author Lucas Giacomazzi
 * @version 1.0, Nov 16, 2011
 */
@Entity
@Table ( name = "establecimiento" )
public class Establecimiento implements Serializable {

    /** Identificador único del objeto. */
    private long idEstablecimiento;
    /** Identificador único del establecimiento real. */
    private long renspa;
    /** Número de la última caravana asignada. */
    private String ultimaCaravana;
    /** Nombre del establecimiento. */
    private String nombre;
    /** Dirección postal del establecimiento. */
    private String direccionPostal;
    /** Provincia donde se encuentra el establecimiento. */
    private String provincia;
    /** Partido donde se encuentra el establecimiento. */
    private String partido;
    /** Lote del establecimiento. */
    private String lote;
    /** Superficie del establecimiento. */
    private int superficie;
    /** Código de verficación del establecimiento. */
    private int codigoVerificacion;
    /** Productor "dueño" del establecimiento. */
    private Productor productor;
    /** Cuig del establecimiento. */
    private String cuig;
    /** Lista de ventas asociadas a este establecimiento. */
    private List<Venta> ventas = new ArrayList<Venta>();
    /** Lista de compras asociadas a este establecimiento. */
    private List<Compra> compras = new ArrayList<Compra>();
    /** Lista de ventas historicas asociadas a este establecimiento. */
    private List<VentaHistorica> ventasHistoricas = new ArrayList<VentaHistorica>();
    /** Lista de compras historicas asociadas a este establecimiento. */
    private List<CompraHistorica> comprasHistoricas = new ArrayList<CompraHistorica>();

    /**
     * Nos devuele el identificador del establecimiento utilizado por Hibernate
     * @return int numero de identificador
     */
    @Id
    @GeneratedValue ( strategy = GenerationType.IDENTITY )
    @Column ( name = "id_establecimiento", nullable = false )
    public long getIdEstablecimiento() {
        return idEstablecimiento;

    }//end método getIdEstablecimiento

    /**
     * Nos devuelve el identificador del establecimiento utilizado por Hibernate. Este método es de uso exclusivo de Hibernate.
     * @param idEstablecimiento int identificador de establecimiento
     */
    protected void setIdEstablecimiento( long idEstablecimiento ) {
        this.idEstablecimiento = idEstablecimiento;

    }//end método setIdEstablecimiento

    /**
     * Nos devuelve los datos del productor al cual pertenece el establecimiento.
     * @return Productor objeto productor
     */
    @ManyToOne ( cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH },
                 optional = false )
    @Cascade ( org.hibernate.annotations.CascadeType.SAVE_UPDATE )
    @JoinColumn ( name = "productor" )
    public Productor getProductor() {
        return this.productor;

    }//end método getProductor

    /**
     * Nos permite modificar el productor al cual pertenece el establecimiento
     * @param productor Productor objeto productor
     */
    public void setProductor( Productor productor ) {
        this.productor = productor;

    }//end método setProductor

    /**
     * Nos permite modificar el código de verificación del establecimiento.
     * @return int código de verificación
     */
    @Column ( name = "cv" )
    public int getCodigoVerificacion() {
        return codigoVerificacion;

    }//end método getCodigoVerificacion

    /**
     * Nos permite modificar el código de verificación
     * @param codigoVerificacion int código de verificación
     */
    public void setCodigoVerificacion( int codigoVerificacion ) {
        this.codigoVerificacion = codigoVerificacion;

    }//end método setCodigoVerificacion

    /**
     * Nos permite obtener la dirección postal del establecimiento.
     * @return String dirección postal
     */
    @Column ( name = "dir_postal", length = 15 )
    public String getDireccionPostal() {
        return direccionPostal;

    }//end método getDireccinPostal

    /**
     * Nos permite modificar la dirección postal del establecimiento
     * @param direccionPostal String dirección postal
     */
    public void setDireccionPostal( String direccionPostal ) {
        this.direccionPostal = direccionPostal;

    }//end método setDireccionPostal

    /**
     * Nos permite obtener el número de lote
     * @return String número de lote
     */
    @Column ( name = "lote", length = 30 )
    public String getLote() {
        return lote;

    }//end método getLote

    /**
     * Nos permite modificar el número de lote
     * @param lote String número de lote
     */
    public void setLote( String lote ) {
        this.lote = lote;

    }//end método setLote

    /**
     * Nos permite obtener el nombre del establecimiento
     * @return String nombre del establecimiento
     */
    @Column ( name = "nombre", nullable = false, length = 30 )
    public String getNombre() {
        return nombre;

    }//end método getNombre

    /**
     * Nos permite modificar el nombre del establecimiento
     * @param nombre String nombre del establecimiento
     */
    public void setNombre( String nombre ) {
        this.nombre = nombre;

    }//end método setNombre

    /**
     * Nos permite obtener el partido del establecimiento
     * @return String nombre del partido
     */
    @Column ( name = "partido", length = 30 )
    public String getPartido() {
        return partido;

    }//end método getPartido

    /**
     * Nos permite modificar el partido al cual pertenece el establecimiento
     * @param partido string partido del establecimiento
     */
    public void setPartido( String partido ) {
        this.partido = partido;

    }//end método setPartido

    /**
     * Nos permite obtener la provincia a la cual pertenece el establecimiento
     * @return String provincia del establecimiento
     */
    @Column ( name = "provincia", length = 30 )
    public String getProvincia() {
        return provincia;

    }//end método getProvincia

    /**
     * Nos permite modificar la provincia a la cual pertenece el establecimiento
     * @param provincia String provincia del establecimiento
     */
    public void setProvincia( String provincia ) {
        this.provincia = provincia;

    }//end método setProvincia

    /**
     * Nos permite obtener el número de renspa que identifica al establecimiento
     * @return long número de renspa
     */
    @Column ( name = "renspa", nullable = false )
    public long getRenspa() {
        return renspa;

    }//end método getRenspa

    /**
     * Nos permite modificar el identificador del establecimiento
     * @param renspa long identificador del establecimiento
     */
    public void setRenspa( long renspa ) {
        this.renspa = renspa;

    }//end método setRenspa

    /**
     * Nos permite obtener la superficie del establecimiento
     * @return int superficie del establecimiento
     */
    @Column ( name = "superficie" )
    public int getSuperficie() {
        return superficie;

    }//end método getSuperficie

    /**
     * Nos permite modificar la superficie del establecimiento
     * @param superficie int superficie del establecimiento
     */
    public void setSuperficie( int superficie ) {
        this.superficie = superficie;

    }//end método setSuperficie

    /**
     * Nos permite modificar el numero de cuig que identifica al establecimiento
     * @return String cuig del establecimiento
     */
    @Column ( name = "cuig", nullable = false, unique = true, length = 5 )
    public String getCuig() {
        return cuig;

    }//end método getCuig

    /**
     * Nos permite modificar el cuig que identifica al estableciemiento
     * @param cuig String ciug del establecimiento
     */
    public void setCuig( String cuig ) {
        this.cuig = cuig;

    }//end método setCuig

    /**
     * Nos permite obtener una lista con las ventas realizadas en un establecimiento
     * @return List<Venta> lista de ventas
     */
    @OneToMany ( mappedBy = "establecimiento",
                 cascade = { CascadeType.MERGE, CascadeType.PERSIST, 
                                                CascadeType.REFRESH } )
    @Cascade ( { org.hibernate.annotations.CascadeType.SAVE_UPDATE,
                 org.hibernate.annotations.CascadeType.EVICT } )
    public List<Venta> getVentas() {
        return ventas;

    }//end método getVentas

    /**
     * Nos permite cambiar una lista de ventas de un establecimiento por otra lista de ventas
     * @param ventas List<Venta> lista de ventas
     */
    public void setVentas( List<Venta> ventas ) {
        this.ventas = ventas;

    }//end método setVentas

    /**
     * Nos permite obtener una lista con las compras realizadas en un establecimiento
     * @return List<Compra> lista de compras
     */
    @OneToMany ( mappedBy = "establecimiento",
                 cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH } )
    @Cascade ( { org.hibernate.annotations.CascadeType.SAVE_UPDATE,
                 org.hibernate.annotations.CascadeType.EVICT } )
    public List<Compra> getCompras() {
        return compras;

    }//end método getCompras

    /**
     * Nos permite cambiar una lista de compras de un establecimiento por otra lista de compras
     * @param compras List<Compra> lista de compras
     */
    public void setCompras( List<Compra> compras ) {
        this.compras = compras;

    }//end método setCompras        

    /**
     * Devuelve la última caravana usada por el último animal nacido en el establecimiento.
     * @return número de la última caravana usada.
     */
    @Column ( name = "ultima_caravana" )
    public String getUltimaCaravana() {
        return ultimaCaravana;

    }//end método getUltimaCaravana

    /**
     * Setea el número de la última caravana usada.
     * @param ultimaCaravana última caravana usada.
     */
    public void setUltimaCaravana( String ultimaCaravana ) {
        this.ultimaCaravana = ultimaCaravana;

    }//end método setUltimaCaravana

    /**
     * Devuelve las compras historicas de este establecimiento.
     * @return compras historicas del establecimiento.
     */
    @OneToMany ( mappedBy = "establecimiento",
                 cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH } )
    @Cascade ( { org.hibernate.annotations.CascadeType.SAVE_UPDATE,
                 org.hibernate.annotations.CascadeType.EVICT } )
    public List<CompraHistorica> getComprasHistoricas() {
        return comprasHistoricas;

    }//end método getComprasHistoricas

    /**
     * Setea las compras historicas de este establecimiento.
     * Este método es utilizado exclusivamente por hibernate para
     * setear los datos de las compras historicas del establecimiento
     * recuperados de la base de datos.
     * @param comprasHistoricas compras historicas a setear.
     */
    protected void setComprasHistoricas( List<CompraHistorica> comprasHistoricas ) {
        this.comprasHistoricas = comprasHistoricas;

    }//end método setComprasHistoricas

    /**
     * Devuelve las ventas historicas realizadas por este establecimiento.
     * @return ventas historicas del establecimiento.
     */
    @OneToMany ( mappedBy = "establecimiento",
                 cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH } )
    @Cascade ( { org.hibernate.annotations.CascadeType.SAVE_UPDATE,
                 org.hibernate.annotations.CascadeType.EVICT } )
    public List<VentaHistorica> getVentasHistoricas() {
        return ventasHistoricas;

    }//end método getVentasHistoricas

    /**
     * Setea las ventas historicas de este establecimiento.
     * Este método es utilizado exclusivamente por hibernate para
     * setear los datos de las ventas historicas del establecimiento
     * recuperados de la base de datos.
     * @param ventasHistoricas compras historicas a setear.
     */
    public void setVentasHistoricas( List<VentaHistorica> ventasHistoricas ) {
        this.ventasHistoricas = ventasHistoricas;

    }//end método setVentasHistoricas

    /**
     * Devuelve TODAS las compras realizadas por este establecimiento.
     * @return compras asociadas al establecimiento.
     */
    public List<AbstractCompra> obtenerCompras() {
        List<AbstractCompra> comp = new ArrayList<AbstractCompra>();

        comp.addAll( getCompras() );
        comp.addAll( getComprasHistoricas() );

        return comp;

    }//end método obtenerCompras

    /**
     * Devuelve TODAS las ventas realizadas por este establecimiento.
     * @return ventas asociadas al establecimiento
     */
    public List<AbstractVenta> obtenerVentas() {
        List<AbstractVenta> vent = new ArrayList<AbstractVenta>();

        vent.addAll( getVentas() );
        vent.addAll( getVentasHistoricas() );

        return vent;

    }//end método obtenerVentas
    
    /**
     * Crea una venta sobre este establecimiento.
     * @return venta creada.
     */
    public Venta crearVenta() {
        Venta venta = new Venta( this, new Date() );
        
        if ( Hibernate.isInitialized( ventas ) )
            ventas.add( venta );
        
        return venta;
        
    }//end método crearVenta
    
    /**
     * Crea una compra sobre este establecimiento.
     * @return compra creada.
     */
    public Compra crearCompra() {
        Compra compra = new Compra( this );
        
        if ( Hibernate.isInitialized( compras ) )
            compras.add( compra );
        
        return compra;
        
    }//end método crearCompra

    /**
     * Indica si este establecimiento es igual a otro objeto pasado por parámetros.
     * Si el otro objeto se trata de un {@code Establecimiento} como este,
     * se los considera iguales cuando sus renspas son iguales.
     * @param obj objeto con el cual comparar.
     * @return <li>true si los objetos son equivalentes. 
     *         <li>flase si los objetos no son equivalentes.
     */
    @Override
    public boolean equals( Object obj ) {
        if ( obj == null )
            return false;
        if ( getClass() != obj.getClass() )
            return false;
        final Establecimiento other = (Establecimiento)obj;
        if ( this.renspa != other.renspa )
            return false;
        return true;

    }//end método equals

    /**
     * Devuelve la computación de un número a partir de la renspa del establecimiento,
     * para que el mismo pueda ser insertado en un {@code Set} sin peligro de
     * que se produzcan inconsistencia en los datos.
     * @return código hash del objeto.
     */
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 17 * hash + (int)( this.renspa ^ ( this.renspa >>> 32 ) );
        return hash;

    }//end método hashCode
    
    /**
     * Devuelve el nombre del establecimiento. Es utilizado por el panel de
     * listados
     * @return nombre del establecimiento
     */
    @Override
    public String toString(){
        return nombre;
    }

}//end clase Establecimiento

